package com.flyqiu.flow.core.manage;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.flyqiu.common.user.FlyQiuUserTools;
import com.flyqiu.flow.api.cache.BpmnModelCache;
import com.flyqiu.flow.api.cache.FlyQiuFlowCacheManage;
import com.flyqiu.flow.api.context.FlyQiuFlowGlobalContext;
import com.flyqiu.flow.api.deploy.FlyQiuFlowDeployManage;
import com.flyqiu.flow.api.deploy.IFlowDeploy;
import com.flyqiu.flow.api.element.FlyQiuFlowElementManage;
import com.flyqiu.flow.api.modelSource.FlowModelSourceManage;
import com.flyqiu.flow.bpmn.FlyQiuBpmModeler;
import com.flyqiu.flow.core.FlyQiuModelConvert;
import com.flyqiu.flow.mapper.ProcDeployDefMapper;
import com.flyqiu.flow.mapper.ProcModelSourceMapper;

import com.flyqiu.flow.model.entity.ProcDeployDef;
import com.flyqiu.flow.model.entity.ProcDeploySource;
import com.flyqiu.flow.model.entity.ProcModelSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

/**
 * 模型资源管理器
 */
public class DefaultFlyQiuFlowModelSourceManage implements FlowModelSourceManage {

    private static final Logger log = LoggerFactory.getLogger(DefaultFlyQiuFlowModelSourceManage.class);
    private final FlyQiuFlowCacheManage procCacheManage;

    private final ProcModelSourceMapper procModelSourceMapper;
    private final FlyQiuFlowElementManage procElementManage;

    private final FlyQiuFlowDeployManage procDeployManage;

    private final FlyQiuFlowGlobalContext globalContext;


    private final ProcDeployDefMapper procDeployDefMapper;

    public DefaultFlyQiuFlowModelSourceManage(FlyQiuFlowGlobalContext globalContext) {
        this.globalContext = globalContext;
        this.procElementManage = globalContext.getFlowElementManage();
        this.procCacheManage = globalContext.getFlowCacheManage();
        this.procModelSourceMapper = globalContext.getBeanManage().getMapper(ProcModelSourceMapper.class);
        this.procDeployDefMapper = globalContext.getBeanManage().getMapper(ProcDeployDefMapper.class);
        this.procDeployManage = globalContext.getFlowDeployManage();
    }


    @Override
    public void saveModelEditorSource(String modeKey, JSONObject source) {
        LambdaQueryWrapper<ProcModelSource> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProcModelSource::getModelKey, modeKey);
        ProcModelSource modelSource = procModelSourceMapper.selectOne(wrapper);
        if (modelSource == null) {
            modelSource = new ProcModelSource();
        }
        modelSource.setModelSource(source);
        modelSource.setModelKey(modeKey);
        String tenantId = FlyQiuUserTools.getTenantId();
        modelSource.setTenantId(tenantId);
        if (StringUtils.checkValNull(modelSource.getId())) {
            procModelSourceMapper.insert(modelSource);
        } else {
            procModelSourceMapper.updateById(modelSource);
        }
    }

    @Override
    public JSONObject getModelEditorSource(String modeKey) {
        LambdaQueryWrapper<ProcModelSource> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProcModelSource::getModelKey, modeKey);
        String tenantId = FlyQiuUserTools.getTenantId();
        wrapper.eq(ProcModelSource::getTenantId, tenantId);
        ProcModelSource modelSource = procModelSourceMapper.selectOne(wrapper);
        if (modelSource == null) return null;
        return modelSource.getModelSource();
    }


    public BpmnModelCache getBpmModeler(String deployDefId, boolean exThrow) {
        BpmnModelCache startBpmModeler = procCacheManage.getCacheDataToObject(deployDefId, BpmnModelCache.class);
        if (startBpmModeler != null) return startBpmModeler;
        ProcDeployDef procDeployDef = procDeployDefMapper.selectById(deployDefId);
        if (procDeployDef == null) {
            if (exThrow) {
                throw new RuntimeException("Resource with procDeployId:" + deployDefId + " not found");
            }
            return null;
        }
        return getBpmModeler(procDeployDef, exThrow);
    }

    @Override
    public BpmnModelCache getBpmModeler(ProcDeployDef deployDef, boolean exThrow) {
        if (deployDef == null) {
            if (exThrow) {
                throw new RuntimeException("Resource with deployDef is null");
            }
            return null;
        }
        BpmnModelCache bpmnCache = procCacheManage.getCacheDataToObject(deployDef.getId(), BpmnModelCache.class);
        if (bpmnCache != null) {
            log.debug("缓存中获取BpmnModelCache成功, deployDefId:{}", deployDef.getId());
            return bpmnCache;
        }
        IFlowDeploy deploy = procDeployManage.getDeploy(deployDef.getProcExecuteType());
        JSONObject modelSource = deploy.getModelSource(deployDef.getDeploySourceId());
        if (modelSource == null) {
            log.error("未找到有效的模型发布资源, deployDefId:{}", deployDef.getId());
            return null;
        }
        FlyQiuBpmModeler bpmModeler = FlyQiuModelConvert.convert(procElementManage, modelSource);
        bpmModeler.setDefName(deployDef.getProcDeployName());
        bpmModeler.setDefKey(deployDef.getProcDeployDefKey());
        bpmnCache = new BpmnModelCache(deployDef, bpmModeler);
        procCacheManage.putData(deployDef.getId(), bpmnCache, 10L, TimeUnit.MINUTES);
        return bpmnCache;
    }


    @Override
    public ProcDeploySource deploy(JSONObject modelSource, String deployType, String procDefKey, String procName, String category) {
        return procDeployManage.deploy(modelSource, deployType, procDefKey, procName, category);
    }

}
